package download.itydl.com.sinlethread.services;

import android.content.Context;
import android.content.Intent;
import android.util.Log;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.RandomAccessFile;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.List;

import download.itydl.com.sinlethread.bean.FileInfo;
import download.itydl.com.sinlethread.bean.ThreadInfo;
import download.itydl.com.sinlethread.db.ThreadDao;
import download.itydl.com.sinlethread.db.ThreadDaoImpl;

/**
 * 下载任务类
 *
 * @author howard
 */
public class DownloadTask {

    private FileInfo mFileInfo;
    private Context mContext;
    private ThreadDao mDao;
    public boolean isPause = false;
    private long finished;

    public DownloadTask(FileInfo mFileInfo, Context mContext) {
        this.mFileInfo = mFileInfo;
        this.mContext = mContext;
        mDao = new ThreadDaoImpl(mContext);
    }

    /**
     * 下载开始
     */
    public void downLoad() {
        // 先从数据库获取当前线程信息，用于续传用（单线程），如果是续传效果，表中已经存在下载的长度数据了。
        List<ThreadInfo> threadInfos = mDao.getThread(mFileInfo.getUrl());
        ThreadInfo threadInfo = null;
        if (threadInfos.size() == 0) {
            Log.e("yangdaolong", "--downLoad()--threadInfos.size() == 0");
            // 数据库还没信息--初始化线程信息类
            threadInfo = new ThreadInfo(0, mFileInfo.getUrl(), 0, mFileInfo.getLength(), 0);
        } else {
            Log.e("yangdaolong", "--downLoad()--threadInfos.size() != 0");
            // 只有一个线程。包含上次暂停前的线程信息
            threadInfo = threadInfos.get(0);
        }
        // 开始下载
        new DownloadThread(threadInfo).start();
    }

    class DownloadThread extends Thread {

        /**
         * 一个线程信息，对应一个该线程
         */
        private ThreadInfo mThreadInfo;

        public DownloadThread(ThreadInfo threadInfo) {
            this.mThreadInfo = threadInfo;
        }

        @Override
        public void run() {
            // 向数据库插入线程信息
            if (!mDao.isExists(mThreadInfo.getUrl(), mThreadInfo.getId())) {
                Log.e("yangdaolong", "--run()--mDao.isExists = false");
                mDao.insertThread(mThreadInfo);
            }
            // 访问网络
            HttpURLConnection conn = null;
            RandomAccessFile raf = null;
            InputStream inputStream = null;
            try {
                URL url = new URL(mFileInfo.getUrl());
                conn = (HttpURLConnection) url.openConnection();
                conn.setRequestMethod("GET");
                conn.setConnectTimeout(5000);
                // 设置本次http请求所请求的数据的区间。该线程请求的不应该是整个服务器文件的数据，
                // 而是[该线程所分配的那段区间的数据]。
                // 因此，我要给该线程获取数据的时候分配一个区间范围，表示我只关心这一段。
                // 使用setRequestProperty设置一个Range范围，它的标准写法如下：
                // 已经下载的
                // 新的起始位置为上次下载进度处（实现续传）
                long start = mThreadInfo.getStart() + mThreadInfo.getFinished();
                conn.setRequestProperty("Range", "bytes=" + start + "-" + mThreadInfo.getEnd());

                // 设置文件下载位置,保证每个线程下载的时候是从指定位置下载
                File file = new File(DownLoadService.DOWNLOAD_PATH, mFileInfo.getFileName());
                raf = new RandomAccessFile(file, "rwd");
                // 设置文件写入位置
                raf.seek(start);

                finished += mThreadInfo.getFinished();
                /**
                 * 发送广播，把进度推出去
                 */
                Intent intent = new Intent(DownLoadService.ACTION_UPDATE);

                // 206 - 部分写入
                if (conn.getResponseCode() == 206) {
                    // 开始下载
                    // 读取服务端数据
                    inputStream = conn.getInputStream();
                    byte[] bytes = new byte[1024 * 4];
                    int len = -1;
                    long startTime = System.currentTimeMillis();
                    while ((len = inputStream.read(bytes)) != -1) {

                        // 这段代码放在while最前 要么最后
                        if (isPause) {
                            // 暂停,保存线程信息到表中
                            mDao.updateThread(mFileInfo.getUrl(), mThreadInfo.getId(), finished);
                            return;
                        }

                        // 向文件写入数据
                        raf.write(bytes, 0, len);
                        finished += len;

                        // 减少UI不断刷新
                        if ((System.currentTimeMillis() - startTime) > 500) {
                            startTime = System.currentTimeMillis();
                            int progress = (int)(finished * 100 / mFileInfo.getLength());
                            intent.putExtra("finished", progress);
                            Log.e("yangdaolong", "finished==" + progress + "");
                            mContext.sendBroadcast(intent);
                        }
                    }

                    // 删除线程信息 -- 表中下载完成，数据都要清空
                    mDao.deletThread(mThreadInfo.getUrl(), mThreadInfo.getId());
                }

            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                try {
                    conn.disconnect();
                    raf.close();
                    inputStream.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }

}
